from typing import Final, TypeAlias, Literal, TYPE_CHECKING
import numpy as np

from puzzle.tile import Tile

if TYPE_CHECKING:
    from puzzle.tile import TileDesc


LABEL_MONTH = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
LABEL_DAY = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"]
LABEL_WEEKDAY = ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

class Tiles:
    blank = Tile("blank", "@")

    m_Jan = Tile("month", "Jan")
    m_Feb = Tile("month", "Feb")
    m_Mar = Tile("month", "Mar")
    m_Apr = Tile("month", "Apr")
    m_May = Tile("month", "May")
    m_Jun = Tile("month", "Jun")
    m_Jul = Tile("month", "Jul")
    m_Aug = Tile("month", "Aug")
    m_Sep = Tile("month", "Sep")
    m_Oct = Tile("month", "Oct")
    m_Nov = Tile("month", "Nov")
    m_Dec = Tile("month", "Dec")
    
    d_1 = Tile("day", "1")
    d_2 = Tile("day", "2")
    d_3 = Tile("day", "3")
    d_4 = Tile("day", "4")
    d_5 = Tile("day", "5")
    d_6 = Tile("day", "6")
    d_7 = Tile("day", "7")
    d_8 = Tile("day", "8")
    d_9 = Tile("day", "9")
    d_10 = Tile("day", "10")
    d_11 = Tile("day", "11")
    d_12 = Tile("day", "12")
    d_13 = Tile("day", "13")
    d_14 = Tile("day", "14")
    d_15 = Tile("day", "15")
    d_16 = Tile("day", "16")
    d_17 = Tile("day", "17")
    d_18 = Tile("day", "18")
    d_19 = Tile("day", "19")
    d_20 = Tile("day", "20")
    d_21 = Tile("day", "21")
    d_22 = Tile("day", "22")
    d_23 = Tile("day", "23")
    d_24 = Tile("day", "24")
    d_25 = Tile("day", "25")
    d_26 = Tile("day", "26")
    d_27 = Tile("day", "27")
    d_28 = Tile("day", "28")
    d_29 = Tile("day", "29")
    d_30 = Tile("day", "30")
    d_31 = Tile("day", "31")
    
    w_Mon = Tile("weekday", "Mon")
    w_Tue = Tile("weekday", "Tue")
    w_Wed = Tile("weekday", "Wed")
    w_Thu = Tile("weekday", "Thu")
    w_Fri = Tile("weekday", "Fri")
    w_Sat = Tile("weekday", "Sat")
    w_Sun = Tile("weekday", "Sun")
    
    m_All = [m_Jan, m_Feb, m_Mar, m_Apr, m_May, m_Jun, m_Jul, m_Aug, m_Sep, m_Oct, m_Nov, m_Dec]
    d_All = [d_1, d_2, d_3, d_4, d_5, d_6, d_7, d_8, d_9, d_10, d_11, d_12, d_13, d_14, d_15, d_16, d_17, d_18, d_19, d_20, d_21, d_22, d_23, d_24, d_25, d_26, d_27, d_28, d_29, d_30, d_31]
    w_All = [w_Mon, w_Tue, w_Wed, w_Thu, w_Fri, w_Sat, w_Sun]
    t_All = [blank, m_Jan, m_Feb, m_Mar, m_Apr, m_May, m_Jun, m_Jul, m_Aug, m_Sep, m_Oct, m_Nov, m_Dec, d_1, d_2, d_3, d_4, d_5, d_6, d_7, d_8, d_9, d_10, d_11, d_12, d_13, d_14, d_15, d_16, d_17, d_18, d_19, d_20, d_21, d_22, d_23, d_24, d_25, d_26, d_27, d_28, d_29, d_30, d_31, w_Mon, w_Tue, w_Wed, w_Thu, w_Fri, w_Sat, w_Sun]

    label_tile_map = {t.label : t for t in t_All}

nonBlankLabel_t: TypeAlias = Literal["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","Mon","Tue","Wed","Thu","Fri","Sat","Sun"]


color_t: TypeAlias = tuple[float, float, float]

class OPTIONS:
    """ User options """

    # Visualization
    V_SCALE:              Final =  1.1
    V_WIDTH:              Final =  3 * V_SCALE * 2
    V_HEIGHT:             Final =  3 * np.sin(np.pi / 3) * V_SCALE * 2
    V_EDGE_COLOR:         Final =  (0, 0, 0)
    V_FACE_COLOR_MONTH:   Final =  (1, 0.86, 0.75)
    V_FACE_COLOR_WEEKDAY: Final =  (0.98, 0.89, 0.47)
    V_FACE_COLOR_DAY:     Final =  (0.60, 0.70, 0.90)
    V_FACE_COLOR_BLANK:   Final =  (1, 1, 1)
    V_UNS_COLOR:          Final =  (1, 0, 0)
    V_COMP_COLOR:         Final =  [
        (1, 0, 0),
        (0, 1, 0),
        (0, 0, 1),
        (1, 1, 0),
        (0, 1, 1),
        (1, 0, 1),
        (0.5, 0.5, 0),
        (0.5, 0, 0.5),
        (0.5, 0.5, 0.5),
        (1, 0.5, 0),
    ]

def v_get_face_color_by_td(td: "TileDesc") -> color_t:
    match td.tile.type:
        case "blank":
            return OPTIONS.V_FACE_COLOR_BLANK
        case "month":
            return OPTIONS.V_FACE_COLOR_MONTH
        case "day":
            return OPTIONS.V_FACE_COLOR_DAY
        case "weekday":
            return OPTIONS.V_FACE_COLOR_WEEKDAY
    assert False